package com.coder.rental.security;

import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTPayload;
import com.coder.rental.entity.User;
import com.coder.rental.utils.JwtUtils;
import com.coder.rental.utils.RedisUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.security.core.AuthenticationException;

import java.io.IOException;

/**
 * 验证用户token是否合规，合规则放到SecurityContextHolder中，并允许继续执行，否则不允许执行，直接抛出异常
 */
@Component
public class VerifyTokenFilter extends OncePerRequestFilter {

    @Value("${request.login}")
    private String loginUrl;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private CustomerUserDetailsService customerUserDetailsService;
    @Resource
    private LoginFailHandler loginFailHandler;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        String url=request.getRequestURI();
        //如果是登录操作，直接跳过
        if(loginUrl.equals(url)){
            doFilter(request,response,filterChain);
            return;
        }
        try{
            String token=request.getHeader("token");
            if (StrUtil.isEmpty(token)){
                token=request.getParameter("token");
            }
            if(token==null){
                throw new CustomerAuthenticationException("token为空");
            }
            //设置在redis中token的key值，并从redis中获取token的value,并验证
            String tokenKey="token:"+token;
            String s = redisUtils.get(tokenKey);
            if(s==null){
                throw new CustomerAuthenticationException("token已过期");
            }
            if(!s.equals(token)){
                throw new CustomerAuthenticationException("token错误");
            }
            //获取token所含的username
            JWTPayload jwtPayload = JwtUtils.parseToken(token);
            String userName= (String) jwtPayload.getClaim("username");
            User user= (User) customerUserDetailsService.loadUserByUsername(userName);
            // 创建认证信息，并设置到SecurityContextHolder中
            UsernamePasswordAuthenticationToken authenticationToken=
                    new UsernamePasswordAuthenticationToken(user,
                            null,user.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource()
                    .buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        }catch(AuthenticationException e){
            loginFailHandler.onAuthenticationFailure(request,response,e);
            return;
        }

        // 继续过滤器链的处理
        doFilter(request, response, filterChain);

    }
}
